package com.example.test;

import org.openhitls.crypto.SM2;
import org.junit.Test;
import static org.junit.Assert.*;

public class SM2Test {
    
    @Test
    public void testKeyGeneration() {
        // Create SM2 instance which automatically generates a key pair
        SM2 sm2 = new SM2();
        
        // Get the generated keys
        byte[] publicKey = sm2.getPublicKey();
        byte[] privateKey = sm2.getPrivateKey();
        
        // Verify keys are not null
        assertNotNull("Public key should not be null", publicKey);
        assertNotNull("Private key should not be null", privateKey);
        
        // Print key lengths and first few bytes for verification
        System.out.println("Test: Public key length: " + publicKey.length);
        System.out.println("Test: Private key length: " + privateKey.length);
        
        System.out.print("Test: Public key bytes: ");
        for (int i = 0; i < Math.min(publicKey.length, 16); i++) {
            System.out.printf("%02x", publicKey[i]);
        }
        System.out.println("...");
        
        // Verify key lengths (typical SM2 key lengths)
        assertTrue("Public key length should be greater than 0", publicKey.length > 0);
        assertTrue("Private key length should be greater than 0", privateKey.length > 0);
        
        // Create another instance to verify unique key generation
        SM2 sm2_2 = new SM2();
        byte[] publicKey2 = sm2_2.getPublicKey();
        byte[] privateKey2 = sm2_2.getPrivateKey();
        
        // Verify keys are different
        assertFalse("Different instances should generate different public keys",
                   java.util.Arrays.equals(publicKey, publicKey2));
        assertFalse("Different instances should generate different private keys",
                   java.util.Arrays.equals(privateKey, privateKey2));
    }

    @Test
    public void testEncryptDecrypt() {
        // Create SM2 instance with generated keys
        SM2 sm2 = new SM2();
        
        // Test data
        String originalText = "Hello, SM2 encryption!";
        byte[] originalData = originalText.getBytes();

        // Encrypt data
        byte[] encryptedData = sm2.encryptData(originalData);
        assertNotNull("Encrypted data should not be null", encryptedData);
        assertTrue("Encrypted data should be longer than original", encryptedData.length > originalData.length);

        // Print encrypted data for debugging
        System.out.println("Test: Original data length: " + originalData.length);
        System.out.println("Test: Encrypted data length: " + encryptedData.length);
        System.out.print("Test: First 16 bytes of encrypted data: ");
        for (int i = 0; i < Math.min(encryptedData.length, 16); i++) {
            System.out.printf("%02x", encryptedData[i]);
        }
        System.out.println("...");

        // Decrypt data
        byte[] decryptedData = sm2.decryptData(encryptedData);
        assertNotNull("Decrypted data should not be null", decryptedData);
        assertEquals("Decrypted data length should match original", originalData.length, decryptedData.length);

        // Compare original and decrypted data
        String decryptedText = new String(decryptedData);
        assertEquals("Decrypted text should match original", originalText, decryptedText);
    }

    @Test
    public void testEncryptDecryptWithSeparateInstances() {
        // Generate keys with first instance
        SM2 sm2Generator = new SM2();
        byte[] publicKey = sm2Generator.getPublicKey();
        byte[] privateKey = sm2Generator.getPrivateKey();

        // Create separate instances for encryption and decryption
        SM2 encryptor = new SM2(publicKey, null); // Only public key needed for encryption
        SM2 decryptor = new SM2(null, privateKey); // Only private key needed for decryption

        // Test data
        String testMessage = "Test with separate instances";
        byte[] originalData = testMessage.getBytes();

        // Encrypt with encryptor instance
        byte[] encryptedData = encryptor.encryptData(originalData);
        assertNotNull("Encrypted data should not be null", encryptedData);

        // Print debug info
        System.out.println("Test: Separate instances - Original data length: " + originalData.length);
        System.out.println("Test: Separate instances - Encrypted data length: " + encryptedData.length);

        // Decrypt with decryptor instance
        byte[] decryptedData = decryptor.decryptData(encryptedData);
        assertNotNull("Decrypted data should not be null", decryptedData);

        // Compare results
        String decryptedText = new String(decryptedData);
        assertEquals("Decrypted text should match original", testMessage, decryptedText);
    }

    @Test
    public void testSignAndVerify() {
        // Create SM2 instance with generated keys
        SM2 sm2 = new SM2();
        
        // Test data
        String message = "Hello, SM2 signature!";
        byte[] data = message.getBytes();

        // Sign data
        byte[] signature = sm2.signData(data);
        assertNotNull("Signature should not be null", signature);
        assertTrue("Signature should not be empty", signature.length > 0);

        // Print debug info
        System.out.println("Test: Message length: " + data.length);
        System.out.println("Test: Signature length: " + signature.length);
        System.out.print("Test: First 16 bytes of signature: ");
        for (int i = 0; i < Math.min(signature.length, 16); i++) {
            System.out.printf("%02x", signature[i]);
        }
        System.out.println("...");

        // Verify signature
        boolean isValid = sm2.verifySignature(data, signature);
        assertTrue("Signature should be valid", isValid);
    }

    @Test
    public void testSignAndVerifyWithSeparateInstances() {
        // Generate keys with first instance
        SM2 sm2Generator = new SM2();
        byte[] publicKey = sm2Generator.getPublicKey();
        byte[] privateKey = sm2Generator.getPrivateKey();

        // Create separate instances for signing and verification
        SM2 signer = new SM2(null, privateKey); // Only private key needed for signing
        SM2 verifier = new SM2(publicKey, null); // Only public key needed for verification

        // Test data
        String message = "Test signature with separate instances";
        byte[] data = message.getBytes();

        // Sign with signer instance
        byte[] signature = signer.signData(data);
        assertNotNull("Signature should not be null", signature);

        // Print debug info
        System.out.println("Test: Separate instances - Message length: " + data.length);
        System.out.println("Test: Separate instances - Signature length: " + signature.length);

        // Verify with verifier instance
        boolean isValid = verifier.verifySignature(data, signature);
        assertTrue("Signature should be valid", isValid);

        // Test with modified data (should fail verification)
        byte[] modifiedData = (message + "modified").getBytes();
        boolean isInvalid = verifier.verifySignature(modifiedData, signature);
        assertFalse("Signature should be invalid for modified data", isInvalid);
    }
} 